package com.ruoyi.framework.task;

import com.ruoyi.project.system.domain.SysDoctor;
import com.ruoyi.project.system.domain.TempWeekDaily;
import com.ruoyi.project.system.mapper.SysDoctorMapper;
import com.ruoyi.project.system.mapper.TempWeekDailyMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 近一周医生值班数据生成任务
 * Bean名称：weeklyScheduleTask（Ruoyi界面配置时需用此名称）
 */
@Component("weeklyScheduleTask1") // 明确指定Bean名称，确保界面配置能精准找到
public class WeeklyScheduleTask {
    private static final Logger log = LoggerFactory.getLogger(WeeklyScheduleTask.class);

    @Autowired
    private SysDoctorMapper sysDoctorMapper; // 注入医生表Mapper（确保Mapper接口存在selectByTimeId方法）

    @Autowired
    private TempWeekDailyMapper weekDailyMapper; // 注入值班表Mapper

    // 时间格式定义（线程不安全，避免作为静态变量重复创建，此处简化使用）
    private static final SimpleDateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    // time_id与“星期+上下午”映射（1-14对应一周14个时段）
    private static final Map<Integer, String> TIME_ID_MAP = new HashMap<Integer, String>() {{
        put(1, "周一上午"); put(2, "周一下午");
        put(3, "周二上午"); put(4, "周二下午");
        put(5, "周三上午"); put(6, "周三下午");
        put(7, "周四上午"); put(8, "周四下午");
        put(9, "周五上午"); put(10, "周五下午");
        put(11, "周六上午"); put(12, "周六下午");
        put(13, "周日上午"); put(14, "周日下午");
    }};

    /**
     * 任务核心方法（无参+void返回值，符合Ruoyi定时任务调用规范）
     * 执行频率：每天0点、12点（每半天一次）
     */
    @Transactional(rollbackFor = Exception.class) // 增强事务：任何异常都回滚，避免数据脏读
    public void generateWeeklySchedule() {
        log.info("===== 开始生成近一周医生值班数据 =====");

        try {
            // 1. 清空表中旧数据（避免重复数据）
            weekDailyMapper.truncateTable();
            log.info("已清空temp_week_daily表旧数据");

            // 2. 获取当前基准日期（作为计算近7天的起点）
            Date today = new Date();
            log.info("基准日期：{}", DATE_FORMAT.format(today));

            // 3. 循环生成14个时段（7天×上下午）的值班数据
            List<TempWeekDaily> weekDataList = new ArrayList<>();
            for (Map.Entry<Integer, String> entry : TIME_ID_MAP.entrySet()) {
                int timeId = entry.getKey();
                String timeDesc = entry.getValue();

                // 3.1 计算当前time_id对应的实际日期（如time_id=6→周三下午→当前基准日期的周三）
                Date targetDate = calculateTargetDate(today, timeId);
                if (targetDate == null) {
                    log.warn("time_id={}（{}）：无法计算对应日期，跳过", timeId, timeDesc);
                    continue;
                }

                // 3.2 生成精确到时分的datetime（上午08:00，下午14:00）
                Date datetime = generateDatetime(targetDate, timeDesc.contains("上午"));

                // 3.3 查询该时段值班的医生（调用Mapper的selectByTimeId方法，需确保SQL实现正确）
                List<SysDoctor> doctors = sysDoctorMapper.selectByTimeId(timeId);
                log.info("time_id={}（{}）：查询到{}名值班医生", timeId, timeDesc, doctors.size());

                // 3.4 组装值班数据（字段映射与数据库表完全一致）
                for (SysDoctor doctor : doctors) {
                    // 跳过ID为空或姓名为空的无效医生
                    if (doctor.getId() == null || doctor.getDoctor() == null || doctor.getDoctor().trim().isEmpty()) {
                        log.warn("跳过无效医生：ID={}，姓名={}", doctor.getId(), doctor.getDoctor());
                        continue;
                    }

                    TempWeekDaily record = new TempWeekDaily();
                    record.setDatetime(datetime); // 值班时间（如2025-11-12 14:00:00）
                    record.setDoctorId(doctor.getId()); // 医生ID（关联sys_doctor.id）
                    record.setDoctorName(doctor.getDoctor().trim()); // 医生姓名（去空格，避免脏数据）
                    record.setDepartment(doctor.getDepartment() != null ? doctor.getDepartment().trim() : "未知科室"); // 科室（容错处理）
                    record.setTitle(doctor.getTitle() != null ? doctor.getTitle().trim() : "未知职称"); // 职称（容错处理）
                    // 值班文本：时段+具体时间（如"周三下午 14:00-18:00"）
                    String schedule = doctor.getSchedule() != null ? doctor.getSchedule().trim() : "8:00-18:00";
                    record.setScheduleText(timeDesc + " " + schedule);
                    record.setRemaining(doctor.getRemaining() > 0 ? doctor.getRemaining() : 10); // 剩余名额（容错：至少10个）
                    record.setTimeId(timeId); // 时段ID（1-14）
                    record.setCurrentDate(targetDate); // 值班日期（仅日期，如2025-11-12）
                    weekDataList.add(record);
                }
            }

            // 4. 批量插入近一周值班数据（批量操作提升效率）
            if (!weekDataList.isEmpty()) {
                weekDailyMapper.batchInsert(weekDataList);
                log.info("近一周值班数据生成完成！共{}条记录", weekDataList.size());
            } else {
                log.warn("未查询到任何有效值班医生数据，temp_week_daily表为空");
            }

        } catch (Exception e) {
            log.error("生成近一周值班数据失败！", e);
            throw new RuntimeException("值班数据生成异常，事务已回滚", e); // 抛出异常触发事务回滚
        } finally {
            log.info("===== 近一周值班数据生成流程结束 =====");
        }
    }

    /**
     * 计算time_id对应的实际日期（基于当前基准日期偏移）
     */
    private Date calculateTargetDate(Date today, int timeId) {
        try {
            Calendar cal = Calendar.getInstance();
            cal.setTime(today);
            int todayWeek = cal.get(Calendar.DAY_OF_WEEK); // Calendar：1=周日，2=周一...7=周六

            // 计算time_id对应的星期（1=周一，2=周二...7=周日）
            int targetWeek = (timeId + 1) / 2; // 公式：time_id=1→1，time_id=2→1，...，time_id=14→7

            // 计算日期偏移量（目标日期 - 基准日期的天数差）
            int offset;
            if (targetWeek >= 1 && targetWeek <= 5) { // 周一到周五（Calendar中对应2-6）
                offset = (targetWeek + 1) - todayWeek;
            } else if (targetWeek == 6) { // 周六（Calendar中对应7）
                offset = 7 - todayWeek;
            } else { // 周日（targetWeek=7，Calendar中对应1）
                offset = 1 - todayWeek + 7;
            }
            // 修正偏移量（确保在0-6天内，避免负天数）
            offset = (offset < 0) ? offset + 7 : offset;

            cal.add(Calendar.DATE, offset);
            return cal.getTime();

        } catch (Exception e) {
            log.error("计算time_id={}的目标日期失败", timeId, e);
            return null;
        }
    }

    /**
     * 生成精确到时分的datetime字段
     */
    private Date generateDatetime(Date date, boolean isMorning) {
        try {
            String dateStr = DATE_FORMAT.format(date);
            String timeStr = isMorning ? "08:00:00" : "14:00:00";
            return DATETIME_FORMAT.parse(dateStr + " " + timeStr);
        } catch (ParseException e) {
            log.error("生成datetime失败，日期={}，是否上午={}", date, isMorning, e);
            return new Date(); // 异常时返回当前时间，避免流程中断
        }
    }
}